Sasbdb load - #3913
Conversation
jamescrake-merani
left a comment
There was a problem hiding this comment.
I've made a few comments on the code I'd like you to take a look at.
I've tested with a couple of IDs. The first one worked, but the second one (SASD2B2) had an error that the identifier was invalid, but I'm not sure it is? Unless I am doing something wrong.
Also, are you intending these changes to go into the next major release? There are some things in here that would need to change with the refactoring project, but if its intended to go into the next release then we probably shouldn't do that work now.
Let me know if anything in the review is unclear. I realise some of the changes I've talked about are not straight forward. If it helps, I'm happy to jump on a meeting to discuss, or try to do some of the changes myself.
| def metadata_summary(info: SASBDBDatasetInfo) -> str: | ||
| """Format dataset metadata for dialog status and logging.""" | ||
| lines = [] | ||
| if info.title: |
There was a problem hiding this comment.
I'm not very comfortable with how long, and repetitive this function is but I also can't suggest any easy way of fixing it.
What I would say though is that it might be better if this is a method within the SASDBDatasetInfo class. You could then use a decorator to give each field a full string name to be printed, and then have a print function within the same class to loop over every field in the dataclass, check if its not none, and print it if so.
| return f"{rg_text} Å" | ||
|
|
||
|
|
||
| def _format_i0_line(i0, i0_error=None, style="label") -> str: |
There was a problem hiding this comment.
This appears to have the same pattern as the _format_rg_line function. Would it be better to abstract this logic into one function?
| return None | ||
|
|
||
|
|
||
| def _structural_lines_from_meta(meta: dict) -> list[str]: |
There was a problem hiding this comment.
Some of these functions have the same issue I mentioned in metadata_summary, and perhaps could be solved in a similar way.
|
|
||
| from PySide6 import QtWidgets | ||
|
|
||
| from .sasbdb_api import SASBDBDatasetInfo, downloadDataset, validateDatasetId |
There was a problem hiding this comment.
I think it would be best to use absolute imports rather than relative.
| return None | ||
| normalized = dataset_id.strip().upper() | ||
| if len(normalized) != 7 or not _SASBDB_ID_PATTERN.match(normalized): | ||
| logger.warning("Invalid SASBDB dataset ID: %r", dataset_id) |
Keep .cursor/ on disk for local AI guidance, but ignore it so it is not shipped in the PR again. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Our agent can fix these. Install it.
No quality gates enabled for this code.
Quality Gate Profile: Custom Configuration
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
|
@jamescrake-merani Thanks for the thorough review and for testing with multiple IDs. Yes — this is intended for the next major release (or one after that). I’ve addressed the correctness/UX items and the smaller cleanups from your comments. Larger structural changes (dataclass/decorator display model, async download worker, moving the client out of qtgui) I’m deliberately deferring so we don’t fight the upcoming refactor. On SASD2B2: that was a real bug. Validation was too strict (SAS + 2 letters + digits). It’s now SAS + 4 alphanumeric characters, which matches entries like SASD2B2. |
jamescrake-merani
left a comment
There was a problem hiding this comment.
Ok thanks for your response. This all makes sense to me, and I'm happy to approve this PR in its current state.

Description
This branch adds Load from SASBDB: users can enter a SASBDB dataset ID, fetch metadata and intensity data from the SASBDB REST API, download a local copy, load it through the existing File data pipeline, and enrich the loaded Data1D objects with SASBDB-derived metadata (sample, instrument, publication, Rg, I(0), Dmax, MW, etc.) where the API provides them.
Implementation highlights
sasbdb_loader: Loads the downloaded file via filesWidget.readData, then populate_metadata() merges API fields into data.sample, data.run, data.instrument, data.title, and meta_data['SASBDB_*'] keys. Surfaces a warning if readData returns no datasets.
How Has This Been Tested?
Review Checklist
Sample/Source/meta_datakeys do not break loaders or perspectives.SASBDBDownloadDialogUI.uiis accompanied by regenerated Python UI (convertUI.py/ project build) if required.menu_bar.rst,tools.rst,sasbdb_download_help.rst) matches the menu label and workflow.requestsremains available in the installed dependency set for end users (not only dev tooling).Documentation (check at least one)
Installers
Licensing (untick if necessary)